package com.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.entity.DecisionNodeFact;
import com.demo.mapper.DecisionNodeFactMapper;
import com.demo.service.IDecisionLoadRuleService;
import lombok.extern.slf4j.Slf4j;
import org.drools.core.base.RuleNameStartsWithAgendaFilter;
import org.drools.template.ObjectDataCompiler;
import org.kie.api.KieBase;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.internal.utils.KieHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Classname DecisionLoadRuleServiceImpl
 * @Description 决策树执行实现类
 * @Date 2023/11/15 19:37
 * @Created by Leo825
 */
@Slf4j
@Service
public class DecisionLoadRuleServiceImpl extends ServiceImpl<DecisionNodeFactMapper, DecisionNodeFact> implements IDecisionLoadRuleService {


    @Autowired
    DecisionNodeFactMapper decisionNodeFactMapper;

    @Override
    public String buildRuleByDecisionId(Long decisionId) {
        QueryWrapper<DecisionNodeFact> wrapper = new QueryWrapper<>();
        wrapper.eq("decision_id", decisionId);
        List<DecisionNodeFact> nodeFacts = decisionNodeFactMapper.selectList(wrapper);

        List<Map<String, Object>> conditionMapList = nodeFacts.stream().map(n ->{
            Map<String, Object> conditionMap = new HashMap<>();
            conditionMap.put("ruleNameId", decisionId);
            conditionMap.put("nodeName", n.getNodeName());
            conditionMap.put("nodeId", n.getNodeId());
            conditionMap.put("ruleCondition", n.getRuleConditionStr());
            conditionMap.put("ruleResult", n.getRuleResultStr());
            return conditionMap;
        }).collect(Collectors.toList());

        String drlStr = "";
        try(InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("templates/decision_rule_template.drt");){
            drlStr = new ObjectDataCompiler().compile(conditionMapList, inputStream);
        }catch (Exception e){
            log.info("文件读取异常：", e);
        }
        log.info("规则文件内容：[\n{}]", drlStr);
        return drlStr;

    }

    /**
     * 执行drl字符串规则
     *
     * @param drlStr      规则字符串
     * @param packag      规则包
     * @param drlFineName 规则文件名
     * @param params      规则执行的入参
     * @return 规则执行结果map
     * packag 对应该示例，为模板中的pakage ，即rules，drlFineName=decision_rule_1.drl，入参则是调用接口方提供
     */
    @Override
    public Map<String, Object> executeDrlStr(String drlStr, String packag, String drlFineName, Map<String, Object> params) {
        // 复制参数到另一个map,防止传递方的param发生变化
        Map<String, Object> drlParams = CollectionUtils.isEmpty(params) ? new HashMap<>() : params
                .entrySet()
                .stream()
                .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));
        log.info("paramMap:[\n{}]", drlParams);

        // 加载规则
        KieSession kieSession = rulekieBase(drlStr).newKieSession();

        Map<String, Object> globalMap = new HashMap<>();
        // 注意这个globalMap必须指定
        kieSession.setGlobal("globalMap", globalMap);
        kieSession.setGlobal("log", log);
        kieSession.insert(drlParams);
        // 对应该示例， drlFineName.substring(0, drlFineName.lastIndexOf(".drl")) 结果是：decision_rule_1
        // 根据模板，一个规则文件中的所有规则都是以文件名开头的
        kieSession.fireAllRules(new RuleNameStartsWithAgendaFilter(drlFineName.substring(0, drlFineName.lastIndexOf(".drl"))));
        kieSession.dispose();
        return globalMap;
    }



    /**
     * 将业务规则写到规则库中
     *
     * @param drlStr 动态传入的规则内容
     * @return
     */
    private KieBase rulekieBase(String drlStr) {
        KieHelper helper = new KieHelper();
        KieBase kieBase = null;
        try {
            helper.addContent(drlStr, ResourceType.DRL);
            //为了省事，直接将rule写成activityRule()
            kieBase = helper.build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(kieBase==null) {
            System.out.println("kiebase没有正确生成！！！！！");
        }
        return kieBase;
    }
}
